/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frct_detect_hash.h                                 */
/*  NOTE      = ct里保存协议识别内容的hash                         */
/*  DATE      = 2016/04/15 by guojq                                */
/*******************************************************************/

#include <stdio.h>
#include <unistd.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frhash2.h"
#include "frct_detect_hash.h"

/*******************************************************************************
*  FUNC     :  初始化ct上判断协议用hash
*  ARGS     :
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
Frhash_header* frct_detect_hash_init(unsigned int ui_table_size)
{
    Frhash_header *p_st_header = NULL;
    
    if (ui_table_size <= 0)
        return NULL;
    
    p_st_header = frhash2_create2(ui_table_size);
    if(p_st_header == NULL)
        return NULL;
    
    return p_st_header;
}

/*******************************************************************************
*  FUNC     :  释放节点内容
*  ARGS     :  p_node 
*  RTN      :
*  NOTE     :  
*******************************************************************************/
FR_STATIC void __ct_detect_node_free(Frlist_node* p_node)
{
    Frct_detect_hash *p_detect_node = NULL;
    
    if (p_node && p_node->data)
    {
        p_detect_node = (Frct_detect_hash *)p_node->data;
        if (p_detect_node->p_detect_data)
            frfree(p_detect_node->p_detect_data);
        frfree(p_detect_node);
    }
}

/*******************************************************************************
*  FUNC     :  组成哈希用key
*  ARGS     :  us_proto  (协议)
            :  ui_src    (原地址)
            :  us_sport  (原端口)
            :  ui_dest   (目的地址)
            :  us_dport  (目的端口)
            :  p_key     (保存地址)
            :  ui_key_size(保存地址长度)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
int frct_detect_hash_key(u_short us_proto, char *p_key, unsigned int ui_key_size)
{
    int i_idx=0, i_len;
    u_int *stupid_strict_aliasing_warnings=(u_int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(u_short))
    {
        FRLOG_ERROR_DETAIL("ct hash key err");
        return 0;
    }

    i_len = sizeof(u_short);
    *stupid_strict_aliasing_warnings = us_proto;
    i_idx += i_len;

    return i_idx;
}

/*******************************************************************************
*  FUNC     :  增加ct到hash
*  ARGS     :  p_st_ct  (Conntrack *)
            :  ul_key   (hash key)
*  RTN      :  成功:返回当前ct的节点, 失败:NULL
*  NOTE     :
*******************************************************************************/
Frlist_node *frct_detect_hash_key_add(Conntrack *p_st_ct
                       , char *p_key, int i_key_len, u_short us_proto, void *p_detect_data)
{
    Frlist_node *p_st_node=NULL;
    Frct_detect_hash *p_st_ct_detect = NULL;
    int i_ret_fun;

    if(p_st_ct==NULL || p_st_ct->p_st_hash_detect_data == NULL || p_detect_data==NULL || p_key==NULL || i_key_len <=0)
        return p_st_node;

    p_st_ct_detect = (Frct_detect_hash *)frmalloc(sizeof(Frct_detect_hash));
    if (p_st_ct_detect == NULL)
        return p_st_node;

    p_st_ct_detect->ip_proto = us_proto;
    p_st_ct_detect->p_detect_data = p_detect_data;

    p_st_node = frlist_node_create(p_st_ct_detect);
    if(!p_st_node)
    {
        frfree(p_st_ct_detect);
        return p_st_node;
    }

    i_ret_fun = frhash2_addStr(p_st_ct->p_st_hash_detect_data, p_key, i_key_len, p_st_node);
    if(i_ret_fun == FR_FAIL)
    {
        frfree(p_st_ct_detect);
        frfree(p_st_node);
        return NULL;
    }
    return p_st_node;
}

/*******************************************************************************
*  FUNC     :  增加ct到hash
*  ARGS     :  p_st_ct  (Conntrack *)
            :  us_proto (协议号)
*  RTN      :  FR_SUCC:成功,FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frct_detect_hash_add(Conntrack *p_st_ct
                       , u_short us_proto, void *p_detect_data)
{
    Frlist_node *p_st_node=NULL;
    Frct_detect_hash *p_st_ct_detect = NULL;
    char arr_key[10];
    int i_hash_key_len=0;
    int i_ret_fun;

    if(p_st_ct==NULL || p_st_ct->p_st_hash_detect_data == NULL || p_detect_data==NULL)
        return FR_FAIL;

    p_st_ct_detect = (Frct_detect_hash *)frmalloc(sizeof(Frct_detect_hash));
    if (p_st_ct_detect == NULL)
        return FR_FAIL;

    p_st_ct_detect->ip_proto = us_proto;
    p_st_ct_detect->p_detect_data = p_detect_data;

    p_st_node = frlist_node_create(p_st_ct_detect);
    if(!p_st_node)
    {
        frfree(p_st_ct_detect);
        return FR_FAIL;
    }
    i_hash_key_len = frct_detect_hash_key(us_proto, arr_key, sizeof(arr_key));

    i_ret_fun = frhash2_addStr(p_st_ct->p_st_hash_detect_data, arr_key, i_hash_key_len, p_st_node);
    if(i_ret_fun == FR_FAIL)
    {
        frfree(p_st_ct_detect);
        frfree(p_st_node);
        return FR_FAIL;
    }
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  获取连接的node
*  ARGS     :  us_proto  (协议)
            :  ui_src    (原地址)
            :  us_sport  (原端口)
            :  ui_dest   (目的地址)
            :  us_dport  (目的端口)
*  RTN      :  节点指针:成功， NULL:失败
*  NOTE     :
*******************************************************************************/
Frlist_node *frct_detect_data_get_node(Conntrack *p_st_ct, u_short ip_proto)
{
    Frlist_node *p_st_node=NULL;
    char arr_hash_key[10];
    int i_hash_key_len=0;

    if(p_st_ct==NULL || p_st_ct->p_st_hash_detect_data == NULL)
        return NULL;

    i_hash_key_len = frct_detect_hash_key(ip_proto, arr_hash_key, sizeof(arr_hash_key));
    p_st_node = frhash2_getStr(p_st_ct->p_st_hash_detect_data, arr_hash_key, i_hash_key_len);

    return p_st_node;
}

/*******************************************************************************
*  FUNC     :  获取协议连接多次判断的缓存信息内容
*  ARGS     :  ip_proto  (协议)
*  RTN      :  获取的内容:成功， NULL:失败
*  NOTE     :
*******************************************************************************/
void *frct_detect_data_get(Conntrack *p_st_ct, u_short ip_proto)
{
    Frlist_node *p_st_node=NULL;
    Frct_detect_hash *p_detect_node = NULL;

    p_st_node = frct_detect_data_get_node(p_st_ct, ip_proto);
    if (p_st_node == NULL || p_st_node->data == NULL)
        return NULL;
    
    p_detect_node = (Frct_detect_hash *)p_st_node->data;
    
    return p_detect_node->p_detect_data;
}


/*******************************************************************************
*  FUNC     :  更新协议连接多次判断的缓存信息内容
*  ARGS     :  ip_proto  (协议)
*  RTN      :  获取的内容:成功， NULL:失败
*  NOTE     :
*******************************************************************************/
int frct_detect_data_update(Conntrack *p_st_ct, u_short ip_proto, void *p_detect_data)
{
    Frlist_node *p_st_node=NULL;
    Frct_detect_hash *p_detect_node = NULL;

    p_st_node = frct_detect_data_get_node(p_st_ct, ip_proto);
    if (p_st_node == NULL || p_st_node->data == NULL)
        return FR_FAIL;
    
    p_detect_node = (Frct_detect_hash *)p_st_node->data;
    
    if (p_detect_node->p_detect_data)
        frfree(p_detect_node->p_detect_data);
    
    p_detect_node->p_detect_data = p_detect_data;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除节点,并释放节点的资源
*  ARGS     :  ip_proto    (协议)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frct_detect_hash_del(Conntrack *p_st_ct, u_short ip_proto)
{
    int i_ret = FR_FAIL;
    Frlist_node *p_st_node = NULL;
        
    p_st_node = frct_detect_data_get_node(p_st_ct, ip_proto);
    if (p_st_node == NULL || p_st_node->data == NULL)
        return FR_FAIL;

    i_ret = frhash2_del(p_st_ct->p_st_hash_detect_data, p_st_node, __ct_detect_node_free);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  删除节点,并释放节点的资源
*  ARGS     :  p_st_node    (Frlist_node *)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
int frct_detect_hash_del_node(Conntrack *p_st_ct, Frlist_node *p_st_node)
{
    int i_ret = FR_FAIL;

    if(p_st_ct==NULL || p_st_ct->p_st_hash_detect_data == NULL || p_st_node == NULL)
        return i_ret;

    i_ret = frhash2_del(p_st_ct->p_st_hash_detect_data, p_st_node, __ct_detect_node_free);
    return i_ret;
}

void frct_detect_hash_free(Frhash_header** pp_detect_hash)
{
    if(pp_detect_hash == NULL || *pp_detect_hash == NULL)
        return;
    frhash2_free2(*pp_detect_hash, __ct_detect_node_free);
    *pp_detect_hash = NULL;
    
}
